
/*!
	\file
	\brief Main window.

		\author Igor Mironchik (igor.mironchik at gmail dot com).

        Copyright (c) 2010 - 2011 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// Qt include.
#include <QtGui/QApplication>
#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include <QtGui/QPixmap>
#include <QtGui/QIcon>
#include <QtGui/QTransform>
#include <QtGui/QTreeView>
#include <QtGui/QVBoxLayout>
#include <QtGui/QMenu>
#include <QtGui/QContextMenuEvent>
#include <QtGui/QSortFilterProxyModel>
#include <QtGui/QStyledItemDelegate>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QDoubleSpinBox>

#include <QtCore/QRegExp>

#include <QtSql/QSqlQuery>

// eShopHelper include.
#include <eShopHelper/h/mainwindow.hpp>
#include <eShopHelper/h/correspondence.hpp>
#include <eShopHelper/h/excel.hpp>
#include <eShopHelper/h/currency.hpp>
#include <eShopHelper/h/document.hpp>
#include <eShopHelper/h/settings.hpp>
#include <eShopHelper/h/db.hpp>
#include <eShopHelper/h/model.hpp>

#include <eShopHelper/ui_mainwindow.h>

// C++ include.
#include <map>
#include <utility>


namespace eShopHelper {

static const QString title = QLatin1String( "eShopHelper" );

static const qreal imageSize = 64;

//
// TextEdit
//

//! Editor for the delegate.
class TextEdit
	:	public QPlainTextEdit
{
	Q_OBJECT

signals:
	//! Emited when editing finished.
	void editingFinished( int row, int column );

public:
	TextEdit( QWidget * parent, const QModelIndex & index )
		:	QPlainTextEdit( parent )
		,	m_row( index.row() )
		,	m_column( index.column() )
	{
	}

protected:
	void keyPressEvent( QKeyEvent * e )
	{
		if( ( e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Enter ) ||
			( e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Return ) )
				emit editingFinished( m_row, m_column );
		else
			QPlainTextEdit::keyPressEvent( e );
	}

private:
	int m_row;
	int m_column;
}; // TextEdit


//
// TextDelegate
//

//! Delegate for the text's fileds.
class TextDelegate
	:	public QStyledItemDelegate
{
	Q_OBJECT

signals:
	//! Emitied when data changed.
	void dataChanged( int row, int column );

public:
	TextDelegate( QObject * parent = 0 )
		:	QStyledItemDelegate( parent )
	{
	}

	QSize sizeHint( const QStyleOptionViewItem & option,
		const QModelIndex & index ) const
	{
		Q_UNUSED( option );
		Q_UNUSED( index );

		return QSize( 0, 35 );
	}

	QWidget *
	createEditor( QWidget * parent, const QStyleOptionViewItem & option,
		const QModelIndex & index ) const
	{
		Q_UNUSED( option );

		TextEdit * editor = new TextEdit( parent, index );
		connect( editor, SIGNAL( editingFinished( int, int ) ),
			this, SLOT( slotCommitAndClose( int, int ) ) );
		return editor;
	}

	void
	setEditorData( QWidget * editor, const QModelIndex & index ) const
	{
		TextEdit * e = qobject_cast< TextEdit* > ( editor );
		e->setPlainText( index.data().toString() );
	}

	void
	setModelData( QWidget * editor, QAbstractItemModel * model,
		const QModelIndex & index ) const
	{
		TextEdit * e = qobject_cast< TextEdit* > ( editor );
		model->setData( index, e->toPlainText(), Qt::DisplayRole );
	}

	void updateEditorGeometry( QWidget * editor,
		const QStyleOptionViewItem & option, const QModelIndex & index ) const
	{
		Q_UNUSED( index );
		editor->setGeometry( option.rect );
	}

private slots:
	void slotCommitAndClose( int row, int column )
	{
		TextEdit * editor = qobject_cast< TextEdit* > ( sender() );
		emit commitData( editor );
		emit closeEditor( editor );
		emit dataChanged( row, column );
	}
}; // class TextDelegate


//
// DoubleSpinBox
//

//! Double spinbox for the delegate.
class DoubleSpinBox
	:	public QDoubleSpinBox
{
	Q_OBJECT

signals:
	//! Emited when editing finished.
	void editingFinished( int row, int column );

public:
	DoubleSpinBox( QWidget * parent, const QModelIndex & index )
		:	QDoubleSpinBox( parent )
		,	m_row( index.row() )
		,	m_column( index.column() )
	{
	}

protected:
	void keyPressEvent( QKeyEvent * e )
	{
		if( ( e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Enter ) ||
			( e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Return ) )
				emit editingFinished( m_row, m_column );
		else
			QDoubleSpinBox::keyPressEvent( e );
	}

private:
	int m_row;
	int m_column;
}; // class DoubleSpinBox


//
// DoubleDelegate
//

//! Delegate for the double's fileds.
class DoubleDelegate
	:	public QStyledItemDelegate
{
	Q_OBJECT

signals:
	//! Emitied when data changed.
	void dataChanged( int row, int column );

public:
	DoubleDelegate( QObject * parent = 0 )
		:	QStyledItemDelegate( parent )
	{
	}

	QWidget *
	createEditor( QWidget * parent, const QStyleOptionViewItem & option,
		const QModelIndex & index ) const
	{
		Q_UNUSED( option );

		DoubleSpinBox * editor = new DoubleSpinBox( parent, index );
		editor->setMinimum( 0.0 );
		editor->setMaximum( 999999999.0 );
		editor->setSingleStep( 1.0 );
		connect( editor, SIGNAL( editingFinished( int, int ) ),
			this, SLOT( slotCommitAndClose( int, int ) ) );
		return editor;
	}

	void
	setEditorData( QWidget * editor, const QModelIndex & index ) const
	{
		DoubleSpinBox * e = qobject_cast< DoubleSpinBox* > ( editor );
		e->setValue( index.data().toDouble() );
	}

	void
	setModelData( QWidget * editor, QAbstractItemModel * model,
		const QModelIndex & index ) const
	{
		DoubleSpinBox * e = qobject_cast< DoubleSpinBox* > ( editor );
		model->setData( index, e->value(), Qt::DisplayRole );
	}

	void updateEditorGeometry( QWidget * editor,
		const QStyleOptionViewItem & option, const QModelIndex & index ) const
	{
		Q_UNUSED( index );

		editor->setGeometry( option.rect );
	}

private slots:
	void slotCommitAndClose( int row, int column )
	{
		DoubleSpinBox * editor = qobject_cast< DoubleSpinBox* > ( sender() );
		emit commitData( editor );
		emit closeEditor( editor );
		emit dataChanged( row, column );
	}
}; // class DoubleDelegate


//
// TreeWidget
//

//! My tree widget.
class TreeWidget
	:	public QTreeView
{
	Q_OBJECT

public:
	//! Columns by it's number.
	enum Columns {
		//! Image column.
		ImageColumn = 0,
		//! Name column.
		NameColumn = 1,
		//! Price column.
		PriceColumn = 2,
		//! Description column.
		DescColumn = 3
	}; // enum Columns

public:
	TreeWidget( QSortFilterProxyModel * model, DB * db, QWidget * parent = 0 )
		:	QTreeView( parent )
		,	m_db( db )
		,	m_model( model )
		,	m_textDelegate( new TextDelegate( this ) )
		,	m_doubleDelegate( new DoubleDelegate( this ) )
	{
		setRootIsDecorated( false );
		setWordWrap( true );
		setEditTriggers( QAbstractItemView::DoubleClicked );
		setAllColumnsShowFocus( true );
		setSortingEnabled( true );
		setAlternatingRowColors( true );
		sortByColumn( NameColumn, Qt::AscendingOrder );

		setModel( m_model );

		setItemDelegateForColumn( NameColumn, m_textDelegate );
		setItemDelegateForColumn( DescColumn, m_textDelegate );
		setItemDelegateForColumn( PriceColumn, m_doubleDelegate );

		connect( m_textDelegate, SIGNAL( dataChanged( int, int ) ),
			this, SLOT( slotDataChanged( int, int ) ) );
	}

	//! \return Is there another goods with the same name and description.
	//! \retval false if there is another goods with the same parameters.
	//! \retval true if there is no another goods with the same parameters.
	bool hasIdenticalGoods( const QString & name, const QString & desc )
	{
		const int rowsCount = m_model->rowCount();

		for( int row = 0; row < rowsCount; ++row )
		{
			if( m_model->data( m_model->index( row, NameColumn ) ).toString() == name &&
				m_model->data( m_model->index( row, DescColumn ) ).toString() == desc )
					return false;
		}

		return true;
	}

public slots:
	//! Set name and description as in Excel file.
	void slotSetNameDescFromExcel( int row, const Goods & goods )
	{
		QMessageBox::StandardButton button =
			QMessageBox::warning( this,
				tr( "There is another goods..." ),
				tr( "There is another goods with the same parameters.\n" ) +
				tr( "Replace with the values from the Excel file?" ),
				QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok );

		if( button == QMessageBox::Ok )
		{
			m_model->setData( m_model->index( row, NameColumn ),
				goods.name(), Qt::DisplayRole );
			m_model->setData( m_model->index( row, DescColumn ),
				goods.description(), Qt::DisplayRole );

			m_db->updateUserName( goods.name(), goods.description(),
				goods.name() );
			m_db->updateUserDesc( goods.name(), goods.description(),
				goods.description() );

			sortByColumn( m_model->sortColumn() );
		}
	}

private slots:
	//! Add image to the goods.
	void slotAddImage()
	{
		doAction( Add );
	}

	//! Change image of the goods.
	void slotChangeImage()
	{
		doAction( Change );
	}

	//! Delete image of the goods.
	void slotDeleteImage()
	{
		doAction( Delete );
	}

	//! Data changed by user.
	void slotDataChanged( int row, int column )
	{
		Goods goods = m_model->data( m_model->index( row, column ), Qt::UserRole )
			.value< Goods > ();

		if( hasIdenticalGoods( m_model->data(
			m_model->index( row, NameColumn ) ).toString(),
				m_model->data( m_model->index( row, DescColumn ) ).toString() ) )
		{
			slotSetNameDescFromExcel( row, goods );
			return;
		}

		if( column == NameColumn )
			m_db->updateUserName( goods.name(), goods.description(),
				m_model->data( m_model->index( row, column ) ).toString() );
		else if( column == DescColumn )
			m_db->updateUserDesc( goods.name(), goods.description(),
				m_model->data( m_model->index( row, column ) ).toString() );

		sortByColumn( m_model->sortColumn() );
	}

	//! Delete goods from the list.
	void slotDeleteGoods()
	{
		const QModelIndex index = currentIndex();
		m_model->removeRows( index.row(), 1 );
	}

	//! Find the same goods.
	void slotFindGoods()
	{
		const int rowsCount = m_model->rowCount();
		const QModelIndex index = currentIndex();
		const QString name = m_model->data(
			m_model->index( index.row(), NameColumn ) ).toString();
		const QString desc = m_model->data(
			m_model->index( index.row(), DescColumn ) ).toString();

		for( int row = 0; row < rowsCount; ++row )
		{
			if( row != index.row() )
				if( m_model->data( m_model->index( row, NameColumn ) ).toString()
						== name &&
					m_model->data( m_model->index( row, DescColumn ) ).toString()
						== desc )
				{
					const QModelIndex newIndex = m_model->index( row, NameColumn );
					setCurrentIndex( newIndex );
					scrollTo( newIndex );

					return;
				}
		}

		QMessageBox::information( this, tr( "Finding of the goods..." ),
			tr( "There is no another goods with the same parameters." ) );
	}

protected:
	//! Context menu event.
	virtual void contextMenuEvent( QContextMenuEvent * event )
	{
		static const QIcon addImageIcon = QIcon( ":/img/add_image.png" );
		static const QIcon changeImageIcon = QIcon( ":/img/change_image.png" );
		static const QIcon deleteImageIcon = QIcon( ":/img/delete_image.png" );
		static const QIcon deleteGoodsIcon = QIcon( ":/img/delete_goods.png" );

		const QModelIndex index = currentIndex();

		if( index.isValid() )
		{
			Goods goods = m_model->data( index, Qt::UserRole )
				.value< Goods >();

			QMenu * menu = new QMenu( this );

			if( goods.isWithImage() )
			{
				QAction * change = menu->addAction( changeImageIcon,
					tr( "Change image" ) );
				QAction * del = menu->addAction( deleteImageIcon,
					tr( "Delete image" ) );

				connect( change, SIGNAL( triggered() ),
					this, SLOT( slotChangeImage() ) );
				connect( del, SIGNAL( triggered() ),
					this, SLOT( slotDeleteImage() ) );
			}
			else
			{
				QAction * add = menu->addAction( addImageIcon,
					tr( "Add image" ) );

				connect( add, SIGNAL( triggered() ),
					this, SLOT( slotAddImage() ) );
			}

			menu->addSeparator();

			QAction * deleteGoods = menu->addAction( deleteGoodsIcon,
				tr( "Delete goods" ) );
			QAction * findGoods = menu->addAction( tr( "Find the same goods" ) );

			connect( deleteGoods, SIGNAL( triggered() ),
				this, SLOT( slotDeleteGoods() ) );
			connect( findGoods, SIGNAL( triggered() ),
				this, SLOT( slotFindGoods() ) );

			menu->popup( event->globalPos() );
		}
	}

private:
	//! Possible actions with image.
	enum Action {
		Add,
		Change,
		Delete
	}; // enum Action

	//! Do given action with image.
	void doAction( Action act )
	{
		QString fileName;

		if( act == Add || act == Change )
		{
			fileName = QFileDialog::getOpenFileName( this,
				tr( "Select image..." ),
				"./etc/images/",
				tr( "Image files (*.png *.bmp *.jpg *.jpeg)" ) );
		}

		const QModelIndex index = currentIndex();

		if( index.isValid() )
		{
			Goods goods = m_model->data( index, Qt::UserRole ).value< Goods >();

			if( ( act != Delete && !fileName.isEmpty() ) || act == Delete )
			{
				goods.setImageFileName( fileName );

				QVariant g;
				g.setValue( goods );

				m_model->setData( index, g, Qt::UserRole );

				QPixmap image( fileName );

				m_model->setData( index, ( image.isNull() ? QPixmap()
						: image.scaled( imageSize, imageSize,
							Qt::KeepAspectRatio ) ),
					Qt::DecorationRole );

				switch( act )
				{
					case Add :
					case Change :
						m_db->updateImage( goods.name(), goods.description(),
							fileName );
						break;
					case Delete :
						m_db->deleteImage( goods.name(), goods.description() );
				}
			}
		}
	}

private:
	//! Database interface.
	DB * m_db;
	//! Model.
	QSortFilterProxyModel * m_model;
	//! Text's delegate.
	TextDelegate * m_textDelegate;
	//! Double's delegate.
	DoubleDelegate * m_doubleDelegate;
}; // TreeWidget


//
// MainWindow::PImpl
//

struct MainWindow::PImpl {
	PImpl()
		:	m_view( 0 )
		,	m_model( 0 )
		,	m_sortModel( 0 )
	{}

	//! UI.
	Ui::MainWindow m_ui;
	//! Resultant document.
	Document m_doc;
	//! Name of the document.
	QString m_docName;
	//! Settings of the application.
	Settings m_settings;
	//! Database with image's correspondencies.
	DB m_db;
	//! Main view.
	TreeWidget * m_view;
	//! Model.
	Model * m_model;
	//! Sort proxy model.
	QSortFilterProxyModel * m_sortModel;
}; // struct MainWindow::PImpl


//
// MainWindow
//

MainWindow::MainWindow( QWidget * parent, Qt::WindowFlags f )
	:	QMainWindow( parent, f )
	,	m_pimpl( new PImpl )
{
	m_pimpl->m_ui.setupUi( this );

	init();
}

MainWindow::~MainWindow()
{
}

void
MainWindow::init()
{
	m_pimpl->m_model = new Model( this );
	m_pimpl->m_sortModel = new QSortFilterProxyModel( this );
	m_pimpl->m_sortModel->setSourceModel( m_pimpl->m_model );

	QVBoxLayout * layout = new QVBoxLayout( centralWidget() );
	m_pimpl->m_view = new TreeWidget( m_pimpl->m_sortModel,
		&m_pimpl->m_db, centralWidget() );
	layout->addWidget( m_pimpl->m_view );

	connect( m_pimpl->m_ui.m_exitAction, SIGNAL( triggered() ),
		this, SLOT( slotQuit() ) );

	connect( m_pimpl->m_ui.m_openAction, SIGNAL( triggered() ),
		this, SLOT( slotOpen() ) );

	connect( m_pimpl->m_ui.m_saveAction, SIGNAL( triggered() ),
		this, SLOT( slotSave() ) );

	connect( m_pimpl->m_ui.m_newAction, SIGNAL( triggered() ),
		this, SLOT( slotNew() ) );

	connect( m_pimpl->m_ui.m_currencyAction, SIGNAL( triggered() ),
		this, SLOT( slotCurrency() ) );

	try {
		m_pimpl->m_settings.load();
	}
	catch( const SettingsException & x )
	{
		QMessageBox::warning( this, tr( "Unable to load settings..." ),
			x.whatAsQString() );
	}

	try {
		m_pimpl->m_db.init();
	}
	catch( const DBException & x )
	{
		QMessageBox::critical( this, tr( "Unable to initialize the database..." ),
			x.whatAsQString() );
	}
}

void
MainWindow::setDocName( const QString & fileName )
{
	static const QRegExp regExp( "^.*[\\\\|/]([^\\\\/]*).eshop$" );

	regExp.indexIn( fileName );
	m_pimpl->m_docName = regExp.cap( 1 );

	setWindowTitle( title + " - " + m_pimpl->m_docName );
}

void
MainWindow::slotOpen()
{
	QFileDialog dlg( this, tr( "Select document to open..." ),
		QLatin1String( "./doc" ),
		tr( "eShopHelper Documents (*.eshop)" ) );
	dlg.setFileMode( QFileDialog::ExistingFile );

	if( QDialog::Accepted == dlg.exec() )
	{
		try {
			const QString fileName = dlg.selectedFiles().front();

			m_pimpl->m_doc.readFromFile( fileName );

			setDocName( fileName );

			m_pimpl->m_model->clear();

			processDocument();
		}
		catch( const DocumentException & x )
		{
			QMessageBox::critical( this, tr( "Unable to read document..." ),
				x.whatAsQString() );
		}
	}
}

void
MainWindow::slotSave()
{
	QFileDialog dlg( this, tr( "Select document to save..." ),
		QLatin1String( "./doc" ),
		tr( "eShopHelper Documents (*.eshop)" ) );
	dlg.setFileMode( QFileDialog::AnyFile );
	dlg.setAcceptMode( QFileDialog::AcceptSave );

	if( QDialog::Accepted == dlg.exec() )
	{
		QString fileName = dlg.selectedFiles().front();

		static const QRegExp regExp( "^.*.eshop$" );

		if( !regExp.exactMatch( fileName ) )
			fileName.append( QLatin1String( ".eshop" ) );

		m_pimpl->m_doc.saveIntoFile( fileName );

		setDocName( fileName );

		m_pimpl->m_ui.m_saveAction->setEnabled( false );
	}
}

void
MainWindow::slotNew()
{
	QFileDialog dlg( this, tr( "Select Excel files..." ),
		QString::fromLatin1( "./input" ),
		tr( "Excel files (*.xls)" ) );
	dlg.setFileMode( QFileDialog::ExistingFiles );

	if( QDialog::Accepted == dlg.exec() )
	{
		Document doc;
		const QStringList excelFiles = dlg.selectedFiles();

		foreach( const QString & excelFile, excelFiles )
			doc.addCorrespondence( excelFile, QString() );

		CorrespondenceDlg correspondenceDlg( doc, this );

		if( QDialog::Accepted == correspondenceDlg.exec() )
		{
			m_pimpl->m_doc = correspondenceDlg.document();
			m_pimpl->m_ui.m_saveAction->setEnabled( true );

			m_pimpl->m_model->clear();
			setWindowTitle( title + " - " + tr( "[unsaved]" ) );
			processDocument();
		}
	}
}

void
MainWindow::slotCurrency()
{
	Settings settings = m_pimpl->m_settings;

	CurrencyDialog dlg( settings, this );

	if( QDialog::Accepted == dlg.exec() )
	{
		m_pimpl->m_settings = settings;

		try {
			m_pimpl->m_settings.save();
			recalculatePrices();
		}
		catch( const SettingsException & x )
		{
			QMessageBox::critical( this, tr( "Unable to save settings..." ),
				x.whatAsQString() );
		}
	}
}

void
MainWindow::slotQuit()
{
	if( m_pimpl->m_ui.m_saveAction->isEnabled() )
	{
		QMessageBox::StandardButton button =
			QMessageBox::warning( this, tr( "Document wasn't saved..." ),
				tr( "Save document before exit?" ),
				QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok );

		if( button == QMessageBox::Ok )
			slotSave();
	}

	qApp->quit();
}

namespace /*anonymous */ {

//
// pushIndexesData
//

//! Push data about indexes of currency.
std::map< int, std::map< int, int > >
pushIndexesData()
{
	std::map< int, std::map< int, int > > data;

	data[ 1 ].insert( std::make_pair( 2, 1 ) );
	data[ 1 ].insert( std::make_pair( 3, 2 ) );
	data[ 1 ].insert( std::make_pair( 4, 3 ) );
	data[ 2 ].insert( std::make_pair( 1, 1 ) );
	data[ 2 ].insert( std::make_pair( 3, 2 ) );
	data[ 2 ].insert( std::make_pair( 4, 3 ) );
	data[ 3 ].insert( std::make_pair( 1, 1 ) );
	data[ 3 ].insert( std::make_pair( 2, 2 ) );
	data[ 3 ].insert( std::make_pair( 4, 3 ) );
	data[ 4 ].insert( std::make_pair( 1, 1 ) );
	data[ 4 ].insert( std::make_pair( 2, 2 ) );
	data[ 4 ].insert( std::make_pair( 3, 3 ) );

	return data;
} // pushIndexesData


//
// convertCurrency
//

//! Convert currency.
double
convertCurrency( double price, const Goods & goods, const Settings & settings )
{
	static std::map< int, std::map< int, int > >
		indexes = pushIndexesData();

	if( goods.currency() == settings.currency() )
		return price;
	else
	{
		switch( indexes[ settings.currency() ][ goods.currency() ] )
		{
			case 1 : return price * settings.cur1();
			case 2 : return price * settings.cur2();
			case 3 : return price * settings.cur3();
			default : return price;
		}
	}
} // convertCurrency


//
// calculatePrice
//

//! Calculate price.
double
calculatePrice( const Goods & goods, const Settings & settings )
{
	double price = 0.0;

	if( !goods.isPriceWithVAT() )
		price = price * ( 1 + ( goods.vat() / 100 ) );
	else
		price = goods.price();

	if( settings.isWithVAT() )
		price = price * ( 1 + ( settings.vat() / 100 ) );

	if( settings.currency() == goods.currency() )
		return price;
	else
		return convertCurrency( price, goods, settings );
} // calculatePrice

} /*namespace anonymous */

void
MainWindow::processDocument()
{
	for( Document::CorrepondenciesMap::ConstIterator it =
			m_pimpl->m_doc.correspondencies().begin(),
		last = m_pimpl->m_doc.correspondencies().end();
		it != last; ++it )
	{
		try {
			ExcelFormat::WorkBook excelBook( c_formatFilesPath + "/"
				+ it.value() + "." + c_formatFileExtension );

			for( QList< ExcelFormat::Spreadsheet >::ConstIterator spreadsheetIt =
				excelBook.spreadsheets().begin(),
				lastSpreadsheetIt = excelBook.spreadsheets().end();
				spreadsheetIt != lastSpreadsheetIt; ++spreadsheetIt )
			{
				ExcelTable table( it.key(), *spreadsheetIt );

				Goods goods = table.next();

				while( goods.isGoods() )
				{
					if( !m_pimpl->m_db.isGoodsExists( goods.name(),
						goods.description() ) )
							m_pimpl->m_db.addGoods( goods.name(),
								goods.description() );

					if( m_pimpl->m_view->hasIdenticalGoods( goods.name(),
						goods.description() ) )
					{
						QString imageFileName = m_pimpl->m_db.checkImage( goods.name(),
							goods.description() );

						goods.setImageFileName( imageFileName );

						const int row = m_pimpl->m_model->rowCount();

						m_pimpl->m_model->insertRows( row, 1 );

						if( !imageFileName.isEmpty() )
						{
							QPixmap image( imageFileName );
							m_pimpl->m_model->setData( m_pimpl->m_model->index( row, 0 ),
								image.scaled( imageSize, imageSize, Qt::KeepAspectRatio ),
								Qt::DecorationRole );
						}

						QVariant g;
						g.setValue( goods );

						m_pimpl->m_model->setData( m_pimpl->m_model->index( row, 0 ),
							g, Qt::UserRole );

						const QString name = m_pimpl->m_db.checkUserName(
							goods.name(), goods.description() );

						const QString desc = m_pimpl->m_db.checkUserDesc(
							goods.name(), goods.description() );

						if( !name.isEmpty() )
							m_pimpl->m_model->setData( m_pimpl->m_model->index( row,
								TreeWidget::NameColumn ), name, Qt::DisplayRole );
						else
							m_pimpl->m_model->setData( m_pimpl->m_model->index( row,
								TreeWidget::NameColumn ), goods.name(), Qt::DisplayRole );

						m_pimpl->m_model->setData( m_pimpl->m_model->index( row,
								TreeWidget::PriceColumn ),
							calculatePrice( goods, m_pimpl->m_settings ),
							Qt::DisplayRole );

						if( !desc.isEmpty() )
							m_pimpl->m_model->setData( m_pimpl->m_model->index( row,
								TreeWidget::DescColumn ), desc, Qt::DisplayRole );
						else
							m_pimpl->m_model->setData( m_pimpl->m_model->index( row,
									TreeWidget::DescColumn ),
								goods.description(), Qt::DisplayRole );
					}
					else
					{
						QMessageBox::warning( this,
							tr( "Duplicated goods is not allowed..." ),
							tr( "There is another goods with the same parameters.\n"
								"This goods will not be in the list:\n"
								"Name: " ) + goods.name() + "\n" );
					}

					goods = table.next();
				}
			}
		}
		catch( const ExcelTableException & x )
		{
			QMessageBox::critical( this,
				tr( "Error loading Excel file." ),
				x.whatAsQString() );
		}
		catch( const ExcelFormat::FormatFileException & x )
		{
			QMessageBox::critical( this,
				tr( "Error loading format file." ),
				x.whatAsQString() );
		}
	}

	m_pimpl->m_view->sortByColumn( m_pimpl->m_sortModel->sortColumn() );
}

void
MainWindow::recalculatePrices()
{
	const int count = m_pimpl->m_model->rowCount();

	for( int i = 0; i < count; ++i )
	{
		const QModelIndex index = m_pimpl->m_model->
			index( i, TreeWidget::PriceColumn );

		m_pimpl->m_model->setData( index,
			calculatePrice( m_pimpl->m_model->data( index , Qt::UserRole )
								.value< Goods >(), m_pimpl->m_settings ),
			Qt::DisplayRole );
	}

	m_pimpl->m_view->sortByColumn( m_pimpl->m_sortModel->sortColumn() );
}

} /* namespace eShopHelper */

#include "mainwindow.moc"
